//
//  CHArrayExtensions.m
//  Chocolat
//
//  Created by Pieter Omvlee on 4/19/08.
//  Copyright 2008 Bohemian Coding. All rights reserved.
//

#import "CHArrayExtensions.h"


@implementation NSArray (CHArrayExtensions)

- (id)firstObject
{
  if ([self count] == 0)
    return nil;
  
  return [self objectAtIndex:0];
}

- (id)head
{
  return [self firstObject];
}

- (NSArray *)tail
{
  if ([self count] < 2)
    return [NSArray array];
  
  return [self objectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(1,[self count]-1)]];
}

- (id)end
{
  return [self lastObject];
}

- (NSArray *)front
{
  return [self objectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0,[self count]-1)]];
}

- (NSArray *)reversedArray
{
  NSMutableArray *result = [NSMutableArray array];
  NSEnumerator *e = [self reverseObjectEnumerator];
  id obj = nil;
  while (obj = [e nextObject])
    [result addObject:obj];
  
  return result;
}

- (BOOL)containsObjectOfClass:(Class)aClass
{
  for (id obj in self) {
    if ([obj isKindOfClass:aClass])
      return YES;
  }
  return NO;
}

- (BOOL)containsSingleClass
{
  if ([self count] == 0) return YES;
  
  Class c = [[self firstObject] class];
  for (NSObject *obj in self) {
    if (![obj isKindOfClass:c])
      return NO;
  }
  return YES;
}


- (BOOL)containsObjectFromArray:(NSArray *)anArray
{
  for (id obj in anArray)
    if ([self containsObject:obj])
      return YES;
  
  return NO;
}

- (NSArray *)map:(SEL)sel
{
  return [self map:sel withObject:nil];
}

- (NSArray *)map:(SEL)sel withObject:(id)obj
{
  return [self map:sel withObject:obj withObject:nil];
}

- (NSArray *)map:(SEL)sel withObject:(id)obj1 withObject:(id)obj2
{
  NSMutableArray *result = [NSMutableArray array];
  for (id elem in self)
    [result addObject:[elem performSelector:sel withObject:obj1 withObject:obj2]];
  return result;
}

- (id)deepCopy
{
  return [[NSArray arrayWithArray:[self mutableDeepCopy]] retain];
}

- (id)mutableDeepCopy
{
  NSMutableArray *copy = [[NSMutableArray alloc] init];
  id objCopy;
  for (id obj in self) {
    if ([obj respondsToSelector:@selector(mutableDeepCopy)])
      objCopy = [obj mutableDeepCopy];
    else
      objCopy = [obj copy];
    [copy addObject:[objCopy autorelease]];
  }
  return copy;
}

- (BOOL)containsOnlyObjectsOfClass:(Class)aClass
{
  BOOL first = [[self firstObject] isKindOfClass:aClass];
  if (!first) return NO;
  
  for (NSObject *obj in self)
    if (![obj isKindOfClass:aClass]) return NO;
  return YES;
}

- (void)performSelector:(SEL)sel withEachObjectAsArgumentToTarget:(id)target
{
  for (id obj in self)
    [target performSelector:sel withObject:obj];
}

- (NSArray *)arrayWithOnlyObjectsOfClass:(Class)aClass
{
  NSMutableArray *array = [self mutableCopy];
  [array onlyKeepObjectsFromClass:aClass];
  return [array autorelease];
}

- (BOOL)containsEqualObjects
{
  BOOL equal = YES;
  for (id obj in self)
    equal = equal && [obj isEqual:[self firstObject]];
  
  return equal;
}

- (NSArray *)sortedArrayUsingKey:(NSString *)key
{
  return [self sortedArrayUsingDescriptors:[NSArray arrayWithObject:[[[NSSortDescriptor alloc] initWithKey:key ascending:YES] autorelease]]];
}

- (NSArray *)sortedArrayUsingKeys:(NSArray *)keys
{
  NSMutableArray *descriptors = [[NSMutableArray alloc] init];
  for (NSString *key in keys) {
    [descriptors addObject:[[[NSSortDescriptor alloc] initWithKey:key ascending:YES] autorelease]];
  }
  return [self sortedArrayUsingDescriptors:descriptors];
}
- (NSArray *)arrayByRemovingObject:(id)anObject
{
  NSMutableArray *cpy = [[self mutableCopy] autorelease];
  [cpy removeObject:anObject];
  return cpy;
}

- (NSDictionary *)dictionaryBySplittingArrayUsingKey:(NSString *)aKey
{
  NSMutableDictionary *result = [NSMutableDictionary dictionary];
  
  for (id obj in self) {
    NSString *keyValue = [obj valueForKey:aKey];
    if (!keyValue)
      keyValue = @"";
    
    if ([result valueForKey:keyValue])
      [[result valueForKey:keyValue] addObject:obj];
    else
      [result setValue:[NSMutableArray arrayWithObject:obj] forKey:keyValue];
  }
  
  return result;
}

- (BOOL)isValidIndex:(int)anIndex
{
  return anIndex >= 0 && anIndex < [self count];
}

@end

@implementation NSMutableArray (NSMutableArrayAdditions)

- (void)removeFirstObject {
  if ([self count] >= 0) [self removeObjectAtIndex:0];
}

- (void)insertObjectsFromArray:(NSArray *)array atIndex:(int)index
{
  NSObject *entry = nil;
  for (id obj in array) {
    [self insertObject:entry atIndex:index++];
  }
}

- (void)onlyKeepObjectsFromClass:(Class)aClass
{
  NSMutableArray *r = [NSMutableArray array];
  for (id obj in self) {
    if (![obj isKindOfClass:aClass])
      [r addObject:obj];
  }
  [self removeObjectsInArray:r];
}

- (void)addObjectIfNotNil:(id)obj
{
  if (obj)
    [self addObject:obj];
}

@end
